package cz.fit.dpo.task1;

import java.util.ArrayList;
import java.util.List;

import cz.fit.dpo.task1.commands.ICommand;
import cz.fit.dpo.task1.exceptions.EndOfGameException;
import cz.fit.dpo.task1.exceptions.GamePassedException;
import cz.fit.dpo.task1.utils.Tuple;
import cz.fit.dpo.task1.worlds.World1;

public class Controller {

	public enum gameStates {
		PLAYING, WON, PASSED
	};

	private List<Tuple<World, String>> availableGames;

	private Game game = null;
	private ICommandProvider view = null;

	private gameStates gameState;

	public Controller() {
		availableGames = new ArrayList<Tuple<World, String>>();
		availableGames.add(new Tuple<World, String>(new World1(), World1.NAME));
	}

	public List<Tuple<World, String>> getAvailableGames() {
		return availableGames;
	}

	public void setGame(Game g) {
		this.game = g;
	}

	public Game getGame() {
		return this.game;
	}

	/**
	 * Connects this controller to the view
	 */
	public void connectToView(ICommandProvider view) {
		this.view = view;
		view.setController(this);
	}

	/**
	 * Main method for starting and playing a game
	 */
	public void gameLoop() {
		while (true) {
			try {
				view.printAvailableGames();
				World world = null;
				while (world == null) {
					world = view.getWorld();
				}

				Game game = new Game(world);
				setGame(game);

				view.printStartOfGame(game);

				setGameState(gameStates.PLAYING);
				play();

				view.printEndOfGame(gameState);
			} catch (EndOfGameException e) {
				break;
			}
		}
	}

	private void setGameState(gameStates newGameState) {
		gameState = newGameState;
	}

	public gameStates getGameState() {
		return gameState;
	}

	private void play() throws EndOfGameException {
		boolean printGameState = true;
		while (gameState == gameStates.PLAYING) {
			if (printGameState) {
				view.printGameState(game);
			}
			printGameState = true;
			try {
				ICommand command = view.getNextCommand();
				if (command == null) {
					printGameState = false;
					continue;
				}
				if (command.execute(game, view) && game.isVictory()) {
					setGameState(gameStates.WON);
				}
			} catch (GamePassedException e) {
				setGameState(gameStates.PASSED);
			}
		}
	}
}
